\ifx \allfiles \undefined
\documentclass{book}
\usepackage{rails-handbook-cn}
\begin{document}
\fi
%==============================
\chapter{路由 Routes}
\index{routes}

\section{路由表的精神}
\label{sec:routes_way}
\begin{quote}
  路由表的实质是分发器，机制是匹配。 ——大捕猎爹王二世康斯坦汀诺维奇
\end{quote}

用户提交的是一个HTTP请求，路由器会从上到下，对第一个匹配到的路由规则进行解析。找到对应的控制器和动作，并将参数解析并移交给动作。

\section{语法}
\label{sec:routes_grammar}
路由表的语法项目并不多。但是要写出清晰漂亮的路由表，却要好好动动脑筋。

\subsection{基本语法格式：}
\begin{lstlisting}
`[匹配方式] '[匹配格式]' => '[控制器]\#[动作]', [选项]`
\end{lstlisting}

\noindent 几个例子：
\begin{lstlisting}
match 'products/:id' => 'catalog#view', :as => :view_cata
get 'products/:id' => 'product#show', :as => :show_product
post 'products' => 'product#create'
resources :users
\end{lstlisting}

匹配方式是一些关键字，实质是路由表的一些方法，包含\inlinecode{root, get, post, put, delete, controller, resources}。

匹配格式是一个字符串，类似与正则表达式，并将其中符号部分匹配出来作为参数向控制器传递。

\bigskip
\noindent 选项部分写成\inlinecode{[符号] => [值]}的形式：
\begin{description}
\item[具名路由 :as]就是给这条路由起一个名字，之后可以使用这个名字来使用这个路由，比如在视图中使用\inlinecode{route\_name\_path()}方法，使用这个方法需要传入之前匹配所需要的参数。例子：

\begin{lstlisting}
match 'products/:id' => 'product#view', :as => :show_product
\end{lstlisting}
我们就可以在视图中使用\inlinecode{show\_product\_path(1)}方法来查看id为1的产品。
\end{description}

\subsection{根路由}
\label{sec:routes_root}

根路由指向网站的根目录。一个小建议是将根路由置顶，一来防止不确定因素导致根目录被匹配而提交到了不确定的控制器上，二来网站的根目录的访问量很大，置顶可以加速匹配，当然，你应该根据自己网站的实际情况进行处理。

\begin{lstlisting}
root :to => 'welcome#index'
\end{lstlisting}

\subsection{基于HTTP请求的路由}
\label{sec:routes_http}

根据HTTP请求中的HTTP方法进行匹配。

\begin{lstlisting}
get  'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
\end{lstlisting}


\subsection{基于资源的路由}
\label{sec:routes_resource}

基本格式:
\begin{lstlisting}
resources :objects, [option]
\end{lstlisting}

这将生成以下7条标准HTTP路由规则：

\begin{tabular}{|l|l|l|l|}
\hline
HTTP动词&路径&动作&辅助方法\\
\hline
GET&    /objects&        index&  objects\_path()\\
GET&    /objects/new&    new&    new\_objects\_path()\\
POST&   /objects&        create& objects\_path()\\
GET&    /objects/1&      show&   object\_path(:id)\\
GET&    /objects/1/edit& edit&   edit\_object\_path(:id)\\
PUT&    /objects/1&      update& object\_path(:id)\\
DELETE& /objects/1&      delete& object\_path(:id)\\
\hline
\end{tabular}

\subsection{路由嵌套}
HTTP请求的URL的格式为：\inlinecode{http://yourdomin.com/:controller/:action/:id}，实际上每一个斜杠都划分了一层嵌套。
路由的嵌套才是路由表的精髓。可以简化路由表的编写，同时复杂化路由器的功能。

\paragraph{}整合控制器：
\begin{lstlisting}
controller :sessions do
  get  'login' => :new, :as => :login
  post 'login' => :create
  delete 'logout' => :destroy, :as => :logout
end
\end{lstlisting}

\paragraph{}在资源中定义额外的请求路由：
\begin{lstlisting}
resources :users do
  get 'profile' => 'profiles#show', :as => user_profile
end
\end{lstlisting}

\paragraph{}基于资源的路由嵌套：
\begin{lstlisting}
resources :users do
  resources :articles
  resources :friends
end
\end{lstlisting}

对于Users和Articles的嵌套会产生默认的7条路由规则：

\begin{tabular}{|l|l|l|l|}
\hline
HTTP动词&路径&动作&辅助方法\\
\hline
GET&    /users/1/articles/&       index&  users\_articles\_path(:user\_id)\\
GET&    /users/1/articles/new&    new&    new\_users\_articles\_path(:user\_id)\\
POST&   /users/1/articles/&       create& users\_articles\_path(:user\_id)\\
GET&    /users/1/articles/1&      show&   users\_articlepath(:user\_id, :id)\\
GET&    /users/1/articles/1/edit& edit&   edit\_users\_articlepath(:user\_id, :id)\\
PUT&    /users/1/articles/1&      update& users\_articlepath(:user\_id, :id)\\
DELETE& /users/1/articles/1&      delete& users\_articlepath(:user\_id, :id)\\
\hline
\end{tabular}

\emph{Attention: 在资源嵌套的时候，父亲资源会在所需的参数（如：\inlinecode{:id}）前增加前缀（如：\inlinecode{:users\_id}，不要忘记。}

\subsection{一个路由表语法合集}
\begin{lstlisting}
root :to => 'welcome#index'

match 'products/:id' => 'product#show', :as => :show_product

get  'login' => 'sessions#new', :as => :login
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy', :as => :logout

controller :sessions do
  get  'login' => :new, :as => :login
  post 'login' => :create
  delete 'logout' => :destroy, :as => :logout
end

resources :users do
  get 'profile' => 'profiles#show', :as => user_profile
  resources :articles
  resources :friends
end
\end{lstlisting}

\subsection{过期的语法}
以下这些语法项已经不推荐使用了，有些还具有危险性。

官方在路由表文件中说道：\emph{下面这个路由会让所有的控制器中的所有动作都可以被GET请求所访问到。}这意味着你不想被人访问到的动作有被暴露的风险。
\begin{lstlisting}[language=ruby]
match ':controller(/:action(/:id(.:format)))'
\end{lstlisting}

在描述目标控制器与动作的时候，还有另外一种陈旧的写法，很冗长而不清晰，不推荐：
\begin{lstlisting}[language=ruby]
`[匹配方式] '[匹配格式]', :controller => '[控制器]', :action => '[动作]', [选项]`
\end{lstlisting}

%==============================
\ifx \allfiles \undefined
\end{document}
\fi